//
// Created by Raymoond Tang on 19/4/13.
// Copyright (c) 2013 NUS. All rights reserved.
//
// To change the template use AppCode | Preferences | File Templates.
//



#ifndef __CollisionRange_H_
#define __CollisionRange_H_

#include <iostream>
#include <string>
#include <sstream>

#define GECODE_USED;

#ifdef GECODE_USED
#include <gecode/search.hh>
#include <gecode/float.hh>
#include <gecode/driver.hh>
using namespace Gecode;
#endif
#include "PlayerObject.h"
#include <cmath>


class Robot2D {
public:
    double x,y,yaw;

    Robot2D() : x(0.0),y(0.0) {}

    Robot2D(double x, double y):x(x),y(y){}

    Robot2D(const Robot2D & other) {
      x = other.x;
      y = other.y;
    }

    Robot2D & operator=(const Robot2D & other) {
      x = other.x;
      y = other.y;
      return *this;
    }

    Robot2D operator+ (const Robot2D & param) const {
        Robot2D temp;
        temp.x = x + param.x;
        temp.y = y + param.y;
        return temp;
    }

    Robot2D operator- (const Robot2D & param) const {
        Robot2D temp;
        temp.x = x - param.x;
        temp.y = y - param.y;
        return temp;
    }
    std::string toString() {
        std::stringstream s;
        s <<  "( " << x;
        s << " , " ;
        s << y << " )";
        return s.str();
    }
};

class Segment2D {
public:
    Robot2D start,end;

    Segment2D():start(Robot2D()),end(Robot2D()) {};

    Segment2D(const Robot2D & start, const Robot2D & end): start(start),end(end) {};

    double getLength() {
        return sqrt(pow(start.x - end.x,2.0)+ pow(start.y - end.y,2.0));
    }

    std::string toString() {
        std::stringstream s;
        s << "start: (";
        s << start.x;
        s << " , " ;
        s << start.y;
        s << ") end: (";
        s << end.x;
        s << " , ";
        s << end.y;
        s << ")\n";
        return s.str();
    }
};

#ifndef GECODE_USED

class Space 
{
public:
    Space() {}
    Space( bool, Space&) {}
    virtual ~Space() {}

    void rel( Space&, bool ) {}
};

class FloatVar
{
public:
    FloatVar(Space&, const double, const double) {}
    FloatVar() {}
    virtual ~FloatVar() {}

    float min() { return m_min; }
    float max() { return m_max; }

    operator float() { return m_min; }

    void update(Space&, const double, const double) {}

private:
    float m_min;
    float m_max;
};

template <class TypeName>
class DFS
{
public:
    DFS<TypeName>( const TypeName* pCur ) : m_pCur( pCur ) {}
    ~DFS() {}

    TypeName* next() { return NULL; }
    const TypeName* next() const { return NULL; }

private:
    const TypeName* m_pCur;
};

#endif

class CollisionRange : public Space {

protected:
    FloatVar tc; //collision range minimum
//    FloatVar ct_e; //collision range maximum
    double maxTime;

    PlayerObject obstacle;

    Segment2D path;

public:
    CollisionRange(Segment2D path, PlayerObject obstacle, double timeAllowd);

    CollisionRange(bool share, CollisionRange & c);
    
    ~CollisionRange();

    virtual Space* copy(bool share) {
        return new CollisionRange(share,*this);
    }

    FloatVar getSol() {
        return tc;
    }

    void print() {
        std::cout << tc.min() <<","<< tc.max() << std::endl;
    }
    std::pair<double,double> getRange();

    double getMin();
    double getMax();
};


#endif //__CollisionRange_H_
